/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bef.core.action.query;

import com.inspur.edp.bef.api.be.IBENodeEntity;
import com.inspur.edp.bef.api.be.IBENodeEntityContext;
import com.inspur.edp.cef.entity.changeset.ChangeDetailMerger;
import com.inspur.edp.cef.entity.changeset.ChangeType;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.entity.condition.EntityFilter;
import com.inspur.edp.cef.entity.dependenceTemp.DataValidator;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.entity.entity.IEntityDataCollection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class PaginationDataMerge {

  private EntityFilter filter;
  private java.util.List<IEntityData> dataList;

  public PaginationDataMerge(EntityFilter filter, java.util.List<IEntityData> dataList) {
    DataValidator.checkForNullReference(dataList, "dataList");

    this.filter = filter;
    this.dataList = dataList;
  }

  /**
   * 通过操作类型来执行具体的相关操作
   * @param data
   * @param changeType
   */
  public final void merge(IEntityData data, Optional<ChangeType> changeType) {
    if (!changeType.isPresent()) {
      return;
    }
    switch (changeType.get()) {
      case Added:
        mergeFromAdd(data);
        break;
      case Deleted:
        mergeFromDelete(data.getID());
        break;
      case Modify:
        mergeFromModify(data);
        break;
      default:
        throw new IllegalArgumentException("changeType");
    }
  }

  public final void mergeFromModify(IEntityData data) {

IEntityData existing = dataList.stream().filter(item ->  data.getID().equals(item.getID()))
        .findFirst().orElse(null);
    if (existing != null) {
      dataList.remove(existing);
      dataList.add(removeChild(data));
    }
  }

  public final void mergeFromDelete(String id) {

IEntityData existing = dataList.stream().filter(item -> id.equals(item.getID())).findFirst()
        .orElse(null);
    if (existing != null) {
      dataList.remove(existing);
    }
  }

public void mergeFromDelete(IEntityData data) {
    mergeFromDelete(data.getID());
  }

  public final void mergeFromAdd(IEntityData data) {
    //新增的数据全部放到最后一页
    if (filter != null && filter.getPagination() != null
        && filter.getPagination().getPageIndex() != filter.getPagination().getPageCount()) {
      return;
    }
    dataList.add(removeChild(data));
  }

  private IEntityData removeChild(IEntityData data) {
    if (data == null) {
      return data;
    }

    IEntityData copied = (IEntityData) data.copy();

    HashMap<String, IEntityDataCollection> childs = copied.getChilds();
    if (childs != null) {

      for (Map.Entry<String, IEntityDataCollection> child : childs.entrySet()) {
        if (child.getValue() != null) {
          child.getValue().clear();
        }
      }
    }
    return copied;
  }

  public final IChangeDetail getOwnChange(IBENodeEntity nodeEntity) {

    IChangeDetail currChange = ((IBENodeEntityContext) nodeEntity.getContext()).getCurrentChange();

    IChangeDetail tranChange = ((IBENodeEntityContext) nodeEntity.getContext())
        .getTransactionalChange();

    if (currChange == null && tranChange == null) {
      return null;
    }

    //为了兼容业务代码中直接修改data, listener会收集出modify类型的变更集, 直接merge会报错
    if (tranChange != null) {
      if (tranChange.getChangeType() == ChangeType.Added) {
        return tranChange;
      }
      return ChangeDetailMerger.mergeChangeDetail(currChange, tranChange.clone());
    } else {
      return currChange;
    }
  }
}
